#include "ksp/SerialPort.h"

using namespace Ksp;

#ifdef __linux__
bool SerialPort::Create(const Desc &desc)
{
    fd = open(desc.path.c_str(), O_RDWR);
    if (fd == -1)
    {
        LOGE("Error opening serial port.");
        return false;
    }
    return fd != -1;
}

bool SerialPort::GetState(SerialState &target)
{
    struct termios tty;

    // memset(&tty, 0, sizeof(tty));
    if (tcgetattr(fd, &tty) != 0)
    {
        // perror("Failed to get attributes");
        return false;
    }

    // 获取波特率
    speed_t baud_rate = cfgetospeed(&tty);
    // printf("Baud rate: %d\n", baud_rate);
    target.baudRate = baud_rate;

    // 获取数据位设置
    int data_bits = (tty.c_cflag & CSIZE);
    // printf("Data bits: %d\n", data_bits);
    target.byteSize = data_bits;

    // 获取停止位设置
    int stop_bits = (tty.c_cflag & CSTOPB) ? 2 : 1;
    // printf("Stop bits: %d\n", stop_bits);
    target.stopBits = stop_bits;

    /* 0-4=None,Odd,Even,Mark,Space    */
    // 检查是否启用奇偶校验
    if (tty.c_cflag & PARENB)
    {
        printf("Parity: Enabled\n");

        // 检查奇偶校验类型
        if (tty.c_cflag & PARODD)
        {
            // printf("Parity type: Odd\n");
            target.parityBits = 1;
        }
        else
        {
            // printf("Parity type: Even\n");
            target.parityBits = 2;
        }
    }
    else
    {
        // printf("Parity: Disabled\n");
        target.parityBits = 0;
    }

    return true;
}

bool SerialPort::SetState(const SerialState &source)
{
    struct termios tty;

    if (tcgetattr(fd, &tty) != 0)
    {
        perror("Failed to get attributes");
        return -1;
    }

    // 设置波特率
    cfsetspeed(&tty, source.baudRate);
    // switch (source.baudRate)
    // {
    // case 9600:
    //     cfsetospeed(&tty, B9600);
    //     cfsetispeed(&tty, B9600);
    //     break;
    // // 可以添加其他波特率设置
    // default:
    //     LOGW("Unsupported baud rate\n");
    //     return false;
    // }

    // 设置数据位
    tty.c_cflag &= ~CSIZE;          // 清除数据位设置
    tty.c_cflag |= source.byteSize; // 设置数据位

    // 设置停止位
    if (source.stopBits == 2)
    {
        tty.c_cflag |= CSTOPB;
    }
    else
    {
        tty.c_cflag &= ~CSTOPB;
    }

    // 设置奇偶校验位
    if (source.parityBits == 0)
    {
        tty.c_cflag &= ~PARENB; // 无奇偶校验
    }
    else
    {
        tty.c_cflag |= PARENB; // 启用奇偶校验
        if (source.parityBits == 1)
        {
            tty.c_cflag &= ~PARODD; // 偶校验
        }
        else
        {
            tty.c_cflag |= PARODD; // 奇校验
        }
    }

    // 其他串口配置参数也可以在这里设置

    if (tcsetattr(fd, TCSANOW, &tty) != 0)
    {
        LOGE("Failed to set attributes");
        return -1;
    }

    return true;
}

#endif

#ifdef _WIN32
bool SerialPort::GetState(SerialState &target)
{
    DCB dcbSerialParams = {0};
    dcbSerialParams.DCBlength = sizeof(dcbSerialParams);

    bool res = GetCommState((HANDLE)fd, &dcbSerialParams);
    if (!res)
    {
        std::cerr << "Failed to get serial port parameters." << std::endl;
        CloseHandle((HANDLE)fd);
        return false;
    }
    target.baudRate = dcbSerialParams.BaudRate;
    target.byteSize = dcbSerialParams.ByteSize;
    target.stopBits = dcbSerialParams.StopBits;
    target.parityBits = dcbSerialParams.Parity;

    return true;
}

bool SerialPort::SetState(const SerialState &source)
{
    DCB dcbSerialParams = {0};
    dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
    dcbSerialParams.BaudRate = source.baudRate;
    dcbSerialParams.StopBits = source.stopBits;
    dcbSerialParams.ByteSize = source.byteSize;
    dcbSerialParams.Parity = source.parityBits;

    bool res = SetCommState((HANDLE)fd, &dcbSerialParams);
    if (!res)
    {
        std::cerr << "Failed to set serial port parameters." << std::endl;
        CloseHandle((HANDLE)fd);
        return false;
    }

    return res;
}

bool SerialPort::Create(const Desc &desc)
{

    fd = (int)CreateFileA(
        desc.path.c_str(),            // 串口名称，根据实际情况修改
        GENERIC_READ | GENERIC_WRITE, // 读取权限
        0,                            // 共享模式，0表示独占访问
        NULL,                         // 安全性描述符
        OPEN_EXISTING,                // 打开已存在的串口
        0,                            // 属性和标志
        NULL                          // 模板文件句柄
    );

    bool res = (fd != -1);
    if (res)
    {
        LOGI("create serial port successfully");
    }
    return res;
}

#endif